package com.connector.server.server;

import com.connector.base.message.MessageHandler;
import io.netty.channel.ChannelOption;
import io.netty.bootstrap.ServerBootstrap;
import com.connector.base.exception.ExceptionHandler;
import com.connector.server.handler.HeartBeatServerHandler;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.timeout.IdleStateHandler;
import java.util.concurrent.TimeUnit;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.EventLoopGroup;
import com.connector.server.handler.HandShakeCheckHandler;
import com.connector.server.handler.ChatHandler;
import com.connector.server.handler.HeartBeatHandler;
import com.connector.server.handler.HandshakeHandler;
import com.connector.base.protocol.Command;
import com.connector.base.message.PacketReceiver;
import com.connector.base.config.InstantConfig;
import com.connector.base.connection.ConnectionRegistry;
import com.connector.server.InstantServer;
import com.connector.base.message.impl.MessageDispatcher;
import io.netty.channel.ChannelHandler;
import com.connector.base.server.NettyTcpServer;

public class WebSocketServer extends NettyTcpServer
{
    private final ChannelHandler channelHandler;
    private MessageDispatcher messageDispatcher;
    private final InstantServer instantServer;
    private final ConnectionRegistry connectionRegistry;

    public WebSocketServer(final InstantServer instantServer) {
        super(InstantConfig.server.websocket.port);
        this.instantServer = instantServer;
        this.messageDispatcher = new MessageDispatcher();
        this.connectionRegistry = instantServer.getConnectionRegistry();
        this.channelHandler = (ChannelHandler)new WebSocketChannelHandler(this.connectionRegistry, (PacketReceiver)this.messageDispatcher);
    }

    public void init() {
        super.init();
        this.messageDispatcher.register(Command.HANDSHAKE, () -> new HandshakeHandler(this.instantServer));
        this.messageDispatcher.register(Command.HEARTBEAT, () -> new HeartBeatHandler());
        this.messageDispatcher.register(Command.CHAT, () -> new ChatHandler());
        this.messageDispatcher.register(Command.HANDSHAKECHECK, () -> new HandShakeCheckHandler());
    }

    public void start() {
        super.start();
    }

    public void stop() {
        super.stop();
    }

    public EventLoopGroup getBossGroup() {
        return (EventLoopGroup)new NioEventLoopGroup();
    }

    public EventLoopGroup getWorkerGroup() {
        return (EventLoopGroup)new NioEventLoopGroup();
    }

    protected void initPipeline(final ChannelPipeline pipeline) {
        pipeline.addLast(new ChannelHandler[] { (ChannelHandler)new IdleStateHandler(30L, 0L, 0L, TimeUnit.SECONDS) });
        pipeline.addLast(new ChannelHandler[] { (ChannelHandler)new HttpServerCodec() });
        pipeline.addLast(new ChannelHandler[] { (ChannelHandler)new HttpObjectAggregator(65536) });
        pipeline.addLast(new ChannelHandler[] { (ChannelHandler)new ChunkedWriteHandler() });
        pipeline.addLast(new ChannelHandler[] { (ChannelHandler)new WebSocketServerProtocolHandler(InstantConfig.server.websocket.wsPath, (String)null, true) });
        pipeline.addLast(new ChannelHandler[] { (ChannelHandler)new WebSocketIndexPageHandler() });
        pipeline.addLast(new ChannelHandler[] { this.getChannelHandler() });
        pipeline.addLast(new ChannelHandler[] { (ChannelHandler)new HeartBeatServerHandler() });
        pipeline.addLast(new ChannelHandler[] { (ChannelHandler)new ExceptionHandler() });
    }

    protected void initOptions(final ServerBootstrap b) {
        super.initOptions(b);
        b.option(ChannelOption.SO_BACKLOG, 1024);
        b.childOption(ChannelOption.SO_SNDBUF,  32768);
        b.childOption(ChannelOption.SO_RCVBUF, 32768);
    }

    public ChannelHandler getChannelHandler() {
        return this.channelHandler;
    }

    public MessageDispatcher getMessageDispatcher() {
        return this.messageDispatcher;
    }

    public InstantServer getInstantServer() {
        return this.instantServer;
    }

    public ConnectionRegistry getConnectionRegistry() {
        return this.connectionRegistry;
    }
}
